home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / ec.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  8KB  |  326 lines

  1. /* Driver for 3COM Ethernet card */
  2.  
  3. #define    TIMER    20000    /* Timeout on transmissions */
  4.  
  5. #include <stdio.h>
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "enet.h"
  9. #include "iface.h"
  10. #include "ec.h"
  11. #include "timer.h"
  12. #include "arp.h"
  13. #include "trace.h"
  14.  
  15. void ec0vec(),ec1vec(),ec2vec();
  16. void (*ecvec[])() = {ec0vec,ec1vec,ec2vec};
  17. struct ec ec[EC_MAX];        /* Per-controller info */
  18. unsigned nec = 0;
  19.  
  20. /* Initialize interface */
  21. int
  22. ec_init(interface,bufsize)
  23. struct interface *interface;
  24. unsigned bufsize;    /* Maximum size of receive queue in PACKETS */
  25. {
  26.     register struct ec *ecp;
  27.     register unsigned base;
  28.     void eaudit();
  29.     unsigned short getcs();
  30.     int16 dev;
  31.  
  32.     dev = interface->dev;
  33.     ecp = &ec[dev];
  34.     base = ecp->base;
  35.     ecp->rcvmax = bufsize;
  36.     ecp->iface = interface;
  37.  
  38.     /* Pulse IE_RESET */
  39.      outportb(IE_CSR(base),IE_RESET);
  40.  
  41.     /* Set interrupt vector */
  42.     if(setirq(ecp->vec,ecvec[dev]) == -1){
  43.         printf("IRQ %u out of range\n",ecp->vec);
  44.         return -1;
  45.     }
  46.     maskon(ecp->vec);    /* Enable interrupt */
  47.     if(interface->hwaddr == NULLCHAR)
  48.         interface->hwaddr = malloc(EADDR_LEN);
  49.     getecaddr(base,interface->hwaddr);
  50.     setecaddr(base,interface->hwaddr);
  51.     if(memcmp(interface->hwaddr,ether_bdcst,EADDR_LEN) == 0){
  52.         printf("EC address PROM contains broadcast address!!\n");
  53.         return -1;
  54.     }
  55.     /* Enable DMA/interrupt request, gain control of buffer */
  56.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  57.  
  58.     /* Enable transmit interrupts */
  59.     outportb(EDLC_XMT(base),EDLC_16 | EDLC_JAM);
  60.  
  61.     /* Set up the receiver interrupts and flush status */
  62.     outportb(EDLC_RCV(base),EDLC_MULTI|EDLC_GOOD|EDLC_ANY|EDLC_SHORT
  63.      |EDLC_DRIBBLE|EDLC_FCS|EDLC_OVER);
  64.     inportb(EDLC_RCV(base));
  65.  
  66.     /* Start receiver */
  67.     outportw(IE_RP(base),0);    /* Reset read pointer */
  68.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  69.     return 0;
  70. }
  71. /* Send raw packet (caller provides header) */
  72. int
  73. ec_raw(interface,bp)
  74. struct interface *interface;    /* Pointer to interface control block */
  75. struct mbuf *bp;        /* Data field */
  76. {
  77.     register struct ec *ecp;
  78.     register unsigned base;
  79.     register int i;
  80.     short size;
  81.  
  82.     ecp = &ec[interface->dev];
  83.     base = ecp->base;
  84.  
  85.     ecp->estats.xmit++;
  86.     dump(interface,IF_TRACE_OUT,TRACE_ETHER,bp);
  87.  
  88.     size = len_mbuf(bp);
  89.     /* Pad the size out to the minimum, if necessary,
  90.      * with junk from the last packet (nice security hole here)
  91.      */
  92.     if(size < RUNT)
  93.         size = RUNT;
  94.     size = (size+1) & ~1;    /* round size up to next even number */
  95.  
  96.     /* Wait for transmitter ready, if necessary. IE_XMTBSY is valid
  97.      * only in the transmit mode, hence the initial check.
  98.      */
  99.     if((inportb(IE_CSR(base)) & IE_BUFCTL) == IE_XMTEDLC){
  100.         for(i=TIMER;(inportb(IE_CSR(base)) & IE_XMTBSY) && i != 0;i--)
  101.             ;
  102.         if(i == 0){
  103.             ecp->estats.timeout++;
  104.             free_p(bp);
  105.             return -1;
  106.         }
  107.     }
  108.     ecp->size = size;
  109.     /* Get control of the board buffer and disable receiver */
  110.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  111.     /* Point GP at beginning of packet */
  112.     outportw(IE_GP(base),BFRSIZ-size);
  113.     /* Actually load each piece with a fast assembler routine */
  114.     while(bp != NULLBUF){
  115.         outbuf(IE_BFR(base),bp->data,bp->cnt);
  116.         bp = free_mbuf(bp);
  117.     }
  118.     /* Start transmitter */
  119.     outportw(IE_GP(base),BFRSIZ-size);
  120.     outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  121.     return 0;
  122. }
  123. /* Ethernet interrupt handler */
  124. int
  125. ecint(dev)
  126. int dev;
  127. {
  128.     register struct ec *ecp;
  129.     register unsigned base;
  130.     struct mbuf *bp;
  131.     int16 size;
  132.     char stat;
  133.  
  134.     ecp = &ec[dev];
  135.     base = ec[dev].base;
  136.     ecp->estats.intrpt++;
  137.  
  138.     /* Check for transmit jam */
  139.     if(!(inportb(IE_CSR(base)) & IE_XMTBSY)){
  140.         stat = inportb(EDLC_XMT(base));
  141.         if(stat & EDLC_16){
  142.             ecp->estats.jam16++;
  143.             rcv_fixup(base);
  144.         } else if(stat & EDLC_JAM){
  145.             /* Crank counter back to beginning and restart transmit */
  146.             ecp->estats.jam++;
  147.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  148.             outportw(IE_GP(base),BFRSIZ - ecp->size);
  149.             outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  150.         }
  151.     }
  152.     for(;;){
  153.         stat = inportb(EDLC_RCV(base));
  154.         if(stat & EDLC_STALE)
  155.             break;
  156.  
  157.         if(stat & EDLC_OVER){
  158.             ecp->estats.over++;
  159.             rcv_fixup(base);
  160.             continue;
  161.         }
  162.         if(stat & (EDLC_SHORT | EDLC_FCS | EDLC_DRIBBLE)){
  163.             ecp->estats.bad++;
  164.             rcv_fixup(base);
  165.             continue;
  166.         }
  167.         if(stat & EDLC_ANY){
  168.             /* Get control of the buffer */
  169.             outportw(IE_GP(base),0);
  170.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  171.         
  172.             /* Allocate mbuf and copy the packet into it */
  173.             size = inportw(IE_RP(base));
  174.             if(size < RUNT || size > GIANT)
  175.                 ecp->estats.bad++;
  176.             else if(ecp->rcvcnt >= ecp->rcvmax)
  177.                 ecp->estats.drop++;
  178.             else if((bp = alloc_mbuf(size)) == NULLBUF)
  179.                 ecp->estats.nomem++;
  180.             else {
  181.                 ecp->estats.recv++;
  182.                 inbuf(IE_BFR(base),bp->data,size);
  183.                 bp->cnt = size;
  184.                 ecp->rcvcnt++;
  185.                 enqueue(&ecp->rcvq,bp);/* Put it on the receive queue */
  186.             }
  187.             outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  188.             outportb(IE_RP(base),0);
  189.         }
  190.     }
  191.     /* Clear any spurious interrupts */
  192.     (void)inportb(EDLC_RCV(base));
  193.     (void)inportb(EDLC_XMT(base));
  194. }
  195. static
  196. rcv_fixup(base)
  197. register unsigned base;
  198. {
  199.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  200.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  201.     outportb(IE_RP(base),0);
  202. }
  203. /* Process any incoming Ethernet packets on the receive queue */
  204. void
  205. ec_recv(interface)
  206. struct interface *interface;
  207. {
  208.     void arp_input();
  209.     int ip_route();
  210.     struct ec *ecp;
  211.     struct mbuf *bp;
  212.  
  213.     ecp = &ec[interface->dev];
  214.     if((bp = dequeue(&ecp->rcvq)) == NULLBUF)
  215.         return;
  216.  
  217.     ecp->rcvcnt--;
  218.     dump(interface,IF_TRACE_IN,TRACE_ETHER,bp);
  219.     eproc(interface,bp);
  220. }
  221. /* Read Ethernet address from controller PROM */
  222. static
  223. getecaddr(base,cp)
  224. register unsigned base;
  225. register char *cp;
  226. {
  227.     register int i;
  228.  
  229.     for(i=0;i<EADDR_LEN;i++){
  230.         outportw(IE_GP(base),i);
  231.         *cp++ = inportb(IE_SAPROM(base));
  232.     }
  233. }
  234. /* Set Ethernet address on controller */
  235. static
  236. setecaddr(base,cp)
  237. register unsigned base;
  238. register char *cp;
  239. {
  240.     register int i;
  241.  
  242.     for(i=0;i<EADDR_LEN;i++)
  243.         outportb(EDLC_ADDR(base)+i,*cp++);
  244. }
  245. /* Shut down the Ethernet controller */
  246. ec_stop(interface)
  247. struct interface *interface;
  248. {
  249.     register unsigned base;
  250.     int16 dev;
  251.  
  252.     dev = interface->dev;
  253.     base = ec[dev].base;
  254.  
  255.     /* Disable interrupt */
  256.     maskoff(ec[dev].vec);
  257.  
  258.     /* Pulse IE_RESET */
  259.     outportb(IE_CSR(base),IE_RESET);
  260.     outportb(IE_CSR(base),0);
  261. }
  262. /* Attach a 3-Com model 3C500 Ethernet controller to the system
  263.  * argv[0]: hardware type, must be "3c500"
  264.  * argv[1]: I/O address, e.g., "0x300"
  265.  * argv[2]: vector, e.g., "3"
  266.  * argv[3]: mode, must be "arpa"
  267.  * argv[4]: interface label, e.g., "ec0"
  268.  * argv[5]: maximum number of packets allowed on receive queue, e.g., "5"
  269.  * argv[6]: maximum transmission unit, bytes, e.g., "1500"
  270.  */
  271. ec_attach(argc,argv)
  272. int argc;
  273. char *argv[];
  274. {
  275.     register struct interface *if_ec;
  276.     extern struct interface *ifaces;
  277.     unsigned dev;
  278.     int ec_init();
  279.     int enet_send();
  280.     int enet_output();
  281.     void ec_recv();
  282.     int ec_stop();
  283.     int pether(),gaether();
  284.  
  285.     arp_init(ARP_ETHER,EADDR_LEN,IP_TYPE,ARP_TYPE,ether_bdcst,pether,gaether);
  286.     if(nec >= EC_MAX){
  287.         printf("Too many Ethernet controllers\n");
  288.         return -1;
  289.     }
  290.     dev = nec++;
  291.     if((if_ec = (struct interface *)calloc(1,sizeof(struct interface))) == NULLIF
  292.      ||(if_ec->name = malloc((unsigned)strlen(argv[4])+1)) == NULLCHAR){
  293.         printf("ec_attach: no memory!\n");
  294.         return -1;
  295.     }
  296.     strcpy(if_ec->name,argv[4]);
  297.     if_ec->mtu = atoi(argv[6]);
  298.     if_ec->send = enet_send;
  299.     if_ec->output = enet_output;
  300.     if_ec->raw = ec_raw;
  301.     if_ec->recv = ec_recv;
  302.     if_ec->stop = ec_stop;
  303.     if_ec->dev = dev;
  304.  
  305.     ec[dev].base = htoi(argv[1]);
  306.     ec[dev].vec = htoi(argv[2]);
  307.  
  308.     if(strcmp(argv[3],"arpa") != 0){
  309.         printf("Mode %s unknown for interface %s\n",
  310.             argv[3],argv[4]);
  311.         free(if_ec->name);
  312.         free((char *)if_ec);
  313.         return -1;
  314.     }
  315.     /* Initialize device */
  316.     if(ec_init(if_ec,(unsigned)atoi(argv[5])) != 0){
  317.         free(if_ec->name);
  318.         free((char *)if_ec);
  319.         return -1;
  320.     }
  321.     if_ec->next = ifaces;
  322.     ifaces = if_ec;
  323.  
  324.     return 0;
  325. }
  326.